package com.alameda.service.impl.user;

import com.alameda.common.base.constant.LoginConstant;
import com.alameda.common.base.enums.UserTypeEnum;
import com.alameda.common.commonpent.redis.api.RedisCacheTemplate;
import com.alameda.common.exception.BusinessException;
import com.alameda.common.utils.*;
import com.alameda.mapper.user.AdUserMapper;
import com.alameda.pojo.user.AdUserDO;
import com.alameda.service.statement.AdSystemRecordService;
import com.alameda.service.user.AdUserService;
import com.alameda.statement.enums.AdSystemRecordEnum;
import com.alameda.user.dto.AdUserDTO;
import com.alameda.user.vo.AdUserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.alameda.common.base.constant.LoginConstant.TOKEN;

/**
 * 用户 业务逻辑层 具体实现
 *
 * @author Lv
 * @date 2024/06/02
 */
@Slf4j
@Service
public class AdUserServiceImpl extends ServiceImpl<AdUserMapper, AdUserDO> implements AdUserService {
    /**
     * 注册账号
     *
     * @param adUserDTO 用户信息
     * @return
     */
    @Override
    public Boolean register(AdUserDTO adUserDTO) {
        // 校验数据
        checkData(adUserDTO);

        // 写入DB
        return this.save(AdUserDO.builder()
                .username(adUserDTO.getUsername())
                .password(MdFiveUtil.getMdFiveString(adUserDTO.getPassword()))
                .nickname(adUserDTO.getNickname())
                .organizationId(adUserDTO.getOrganizationId())
                .email(adUserDTO.getEmail())
                .build());
    }

    @Autowired
    private RedisCacheTemplate redisCacheTemplate;

    @Autowired
    private AdSystemRecordService adSystemRecordService;

    /**
     * 登录系统
     *
     * @param adUserDTO 用户信息
     * @return
     */
    @Override
    public Map<String, Object> login(AdUserDTO adUserDTO) {
        AdUserDO adUserDO = findByUserName(adUserDTO.getUsername());
        if (PubUtils.isNull(adUserDO)) {
            BusinessException.throwException("账号错误");
        }

        if (!adUserDO.getPassword().equals(MdFiveUtil.getMdFiveString(adUserDTO.getPassword()))) {
            BusinessException.throwException("密码错误");
        }

        // 获取用户类型
        Map<String, String> extData = adUserDO.getExtData();
        String type = extData.get(UserTypeEnum.getKeyString());

        //登录成功 生成token
        Map<String, Object> claimMap = new HashMap<>(16);
        claimMap.put(LoginConstant.ID, adUserDO.getId());
        claimMap.put(LoginConstant.USERNAME, adUserDO.getUsername());
        claimMap.put(LoginConstant.USER_TYPE, type);
        String token = JwtUtils.genToken(claimMap);

        // token 写入redis 5个小时过期
        redisCacheTemplate.setCacheObject(token, token, 5, TimeUnit.HOURS);

        Map<String, Object> map = MapUtils.newHashMap();
        map.put(TOKEN, token);

        // 存储系统信息记录
        adSystemRecordService.saveRecord(AdSystemRecordEnum.LOGIN);
        // token写入db
        saveTokenInfo(adUserDO, token);
        return map;
    }

    /**
     * 将token写入数据表
     *
     * @param adUserDO 管理端用户信息
     * @param token    token值
     * @return
     */
    private Boolean saveTokenInfo(AdUserDO adUserDO, String token) {
        Map<String, String> extDataMap = adUserDO.getExtData();
        extDataMap.put(TOKEN, token);
        adUserDO.setExtData(extDataMap);
        return this.updateById(adUserDO);
    }

    /**
     * 获取当前登录用户信息
     *
     * @return
     */
    @Override
    public AdUserVO getUserInfo() {
        String userName = ThreadLocalUtils.getUserName();
        AdUserDO adUserDO = findByUserName(userName);

        AdUserVO adUserVO = ObjectUtils.convert(adUserDO, AdUserVO.class);
        adUserVO.setName("Super Admin");
        adUserVO.setAvatar("https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
        adUserVO.setRoles("admin");
        adUserVO.setIntroduction("***");
        return adUserVO;
    }

    /**
     * 修改用户信息
     *
     * @param adUserDTO 用户信息
     * @return
     */
    @Override
    public Boolean edit(AdUserDTO adUserDTO) {
        AdUserDO adUserDO = ObjectUtils.convert(adUserDTO, AdUserDO.class);
        return this.updateById(adUserDO);
    }

    /**
     * 退出登录
     *
     * @return
     */
    @Override
    public Boolean logout() {
        String token = ThreadLocalUtils.getToken();
        // 移除db中的token
        removeDbToken(token);
        return redisCacheTemplate.deleteObject(token);
    }

    /**
     * 移除db中的token
     *
     * @param token 登录令牌
     * @return
     */
    private Boolean removeDbToken(String token) {
        AdUserDO adUserDO = findByToken(token);
        Map<String, String> extDataMap = adUserDO.getExtData();
        extDataMap.put(TOKEN, null);
        return this.updateById(adUserDO);
    }

    /**
     * 查询用户列表
     *
     * @param adUserDTO 用户信息
     * @return
     */
    @Override
    public IPage<AdUserVO> loadUser(AdUserDTO adUserDTO) {
        log.info("通过子类方法com.alameda.service.user.UserServiceImplExt.loadUser实现");
        return null;
    }

    /**
     * 导出excel
     *
     * @param adUserDTO 用户信息
     */
    @Override
    public void export(AdUserDTO adUserDTO) {
        log.info("通过子类方法com.alameda.service.user.UserServiceImplExt.export实现");
    }

    /**
     * 删除组织下的用户
     *
     * @param organizationIdList 组织id集合
     * @return
     */
    @Override
    public Boolean removeByOrganizationIdList(List<Long> organizationIdList) {
        log.info("通过子类方法com.alameda.service.user.UserServiceImplExt.removeByOrganizationIdList实现");
        return null;
    }

    /**
     * 处理管理端token续期
     *
     * @param token 登录令牌
     * @return
     */
    @Override
    public Boolean dealAdUserTokenRenewal(String token) {
        log.info("通过子类方法com.alameda.service.impl.user.AdUserServiceImplExt.dealAdUserTokenRenewal实现");
        return null;
    }

    /**
     * 通过登录令牌获取用户信息
     *
     * @param token 登录令牌
     * @return
     */
    @Override
    public AdUserDO findByToken(String token) {
        LambdaQueryWrapper<AdUserDO> lambdaQueryWrapper = Wrappers.lambdaQuery(AdUserDO.class).apply("ext_data ->> '$.token' = {0}", token);
        return this.getOne(lambdaQueryWrapper);
    }

    /**
     * 最小长度
     */
    private static final Short MIN_LENGTH = 5;

    /**
     * 最大长度
     */
    private static final Short MAX_LENGTH = 16;

    /**
     * 校验数据
     *
     * @param adUserDTO 用户信息
     */
    private void checkData(AdUserDTO adUserDTO) {
        String username = adUserDTO.getUsername();
        if (PubUtils.isEmpty(username) || username.length() < MIN_LENGTH || username.length() > MAX_LENGTH) {
            BusinessException.throwException("注册账号有误");
        }

        AdUserDO adUserDO = findByUserName(username);
        if (PubUtils.isNotNull(adUserDO)) {
            BusinessException.throwException("账号已注册");
        }

        String password = adUserDTO.getPassword();
        if (PubUtils.isEmpty(password) || password.length() < MIN_LENGTH || password.length() > MAX_LENGTH) {
            BusinessException.throwException("注册密码有误");
        }
    }
}
